<?php

namespace StudyBuddy;

/**
 * Class responsible for
 * upserting (update or insert)
 * array of tags that belong to one question
 * into QUESTION_TAGS collection
 */
class Qtagscounter extends StudyBuddyObject {

    /**
     * Mongo collection QUESTION_TAGS
     *
     * @var object of type MongoCollection for QUESTION_TAGS
     */
    protected $coll;

    public function __construct(Registry $oRegistry) {
        $this->oRegistry = $oRegistry;
        $this->coll = $oRegistry->Mongo->QUESTION_TAGS;
    }

    /**
     * Parse one question, upserting its' tags
     * into QUESTION_TAGS collection
     *
     * Why do we care so much about having accurate timestamp
     * of the last time tag was inserted?
     *
     * It's because we use it when showing recent tags
     * block. We use timestamps as offset to show tags
     * in the past week or month or whatever.
     *
     * We don't want to rely on timestamp from
     * external API. But then we will have mismatch of timestamps
     * if API timestamp is way off, then our tags counter
     * is updated with out time while question stamped with
     * API's timestamp so count of n for tags will be wrong
     * when we actually viewing the page.
     *
     * We must either trust external API's timestamp or don't
     *  trust it. We can't trust it in one collection
     *  and not trust it in another.
     *  It will be a hell of a lot easier if we just
     *  trust external API's timestamp
     *
     *  @todo we can use this as post-echo method
     *
     * @param Question $oQuestion
     * @return object $this
     */
    public function parse(Question $oQuestion, array $aExtra = array()) {
        $aTags = $oQuestion['a_tags'];
        $time = $oQuestion['i_ts'];

        if (!empty($aTags)) {
            $set = array('i_ts' => $time, 'hts' => date("F j, Y g:i a"));
            if (!empty($aExtra)) {
                $set = $set + $aExtra;
                // d('new $set: '.print_r($set, 1));
            }

            $this->coll->ensureIndex(array('tag' => 1), array('unique' => true));
            $this->coll->ensureIndex(array('i_count' => 1));

            foreach ($aTags as $tag) {
                /**
                 * Sanity check, even though there aren't supposed
                 * to be any way to sneak an empty tag into
                 * a question, but just in case... because it's just that important
                 * to not allow empty values or Mongo will throw Exception
                 */
                if (!empty($tag)) {
                    try {
                        $this->coll->update(array("tag" => $tag), array('$inc' => array("i_count" => 1), '$set' => $set), array("upsert" => true));
                    } catch (\MongoException $e) {
                        //e('unable to upsert into QUESTION_TAGS : '.$e->getMessage());
                    }
                }
            }
        }

        return $this;
    }

    /**
     * When question is deleted or retagged
     * we must update the collection
     * to decrease number of tags count to account
     * for this removed question
     *
     * @param Question $oQuestion
     *
     * @return object $this;
     */
    public function removeTags($oQuestion) {
        if (!is_array($oQuestion) && (!($oQuestion instanceof \StudyBuddy\Question))) {
            throw new \InvalidArgumentException('$oQuestion must be array OR instance of Question. was: ' . gettype($oQuestion));
        }

        $aTags = (is_array($oQuestion)) ? $oQuestion : $oQuestion['a_tags'];

        if (!empty($aTags)) {
            /**
             * In theory the $tag will exist
             * because it has been inserted there when
             * this question was created and the count is at least 1
             *
             * The only possible problem is that the count will be set
             * to 0 instead of deleting a tag, but this
             * is not really a problem we can just not show tags
             * that have 0 count
             */
            foreach ($aTags as $tag) {
                if (!empty($tag)) {
                    try {
                        /**
                         * Do this extra step to find current count
                         * then remove tag if count is NOT positive integer,
                         * otherwise decrease it
                         *
                         * This way we avoid the possibility of setting
                         * the i_count to 0 or -1
                         */
                        $a = $this->coll->findOne(array('tag' => $tag), array('i_count'));
                        d('a: ' . var_export($a, 1));
                        if ($a && ($a['i_count'] > 0)) {
                            $this->coll->update(array("tag" => $tag), array('$inc' => array("i_count" => -1)));
                        } else {
                            $this->coll->remove(array("tag" => $tag), array('safe' => true));
                        }
                    } catch (\MongoException $e) {
                        e('unable to update (decrease count) QUESTION_TAGS : ' . $e->getMessage());
                    }
                }
            }
        }

        return $this;
    }

}
